package com.sven.sharedb.core.utils;

import com.sven.sharedb.core.constants.ShardingConstants;
import com.sven.sharedb.core.entity.ShardingTableDateRange;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 创建日期按量分片工具类
 *
 * @author sven.wang
 * @version 2022/6/30 16:33
 */
@Slf4j
public class ShardingContUtils {


    /**
     * 根据实际节点获取表信息
     * @param actualDataNodes 实际节点
     * @return 表信息
     */
    public static List<ShardingTableDateRange> getTableInfoByActualDataNodes(String actualDataNodes) {
        //表名节点
        List<String> nodes = Arrays.asList(actualDataNodes.split(","));
        if(CollectionUtils.isEmpty(nodes)){
            return Collections.emptyList();
        }
        return getTableInfo(nodes.stream().map(item -> item.replace(ShardingConstants.RULE_CONFIG_NAME + ShardingConstants.SPLIT_POINT,"")).collect(Collectors.toList()));
    }

    /**
     * 获取表信息
     * @param tableNames 表名数组
     * @return 表信息
     */
    public static List<ShardingTableDateRange> getTableInfo(List<String> tableNames) {
        List<ShardingTableDateRange> shardingTableDateRanges = new ArrayList<>();
        //如果所有表信息只有主表,则按时段默认值设置
        if(tableNames.size() == 1){
            String item = tableNames.get(0);
            ShardingTableDateRange shardingTableDateRange = new ShardingTableDateRange();
            shardingTableDateRange.setTableName(item);
            shardingTableDateRange.setTableNameDateTime(getTableNameDateTime(item));
            shardingTableDateRange.setEndDate(DateTimeUtils.str2Date(ShardingConstants.DB_SHARDING_TABLES_MAIN_DEFAULT_END, DateTimeUtils.FORMAT_yyyyMMddHHmmss));
            shardingTableDateRange.setBeginDate(DateTimeUtils.str2Date(ShardingConstants.DB_SHARDING_TABLES_MAIN_DEFAULT_BEGIN, DateTimeUtils.FORMAT_yyyyMMddHHmmss));
            shardingTableDateRanges.add(shardingTableDateRange);
            return shardingTableDateRanges;
        }
        List<ShardingTableDateRange> tableInfos = tableNames.stream()
                .map(item -> {
                    ShardingTableDateRange shardingTableDateRange = new ShardingTableDateRange();
                    shardingTableDateRange.setTableName(item);
                    shardingTableDateRange.setTableNameDateTime(getTableNameDateTime(item));
                    return shardingTableDateRange;
                })
                //根据表名时间正序排
                .sorted(Comparator.comparing(ShardingTableDateRange::getTableNameDateTime
                        //如果M为空则放最后前面
                        ,Comparator.nullsFirst(Date::compareTo)))
                .collect(Collectors.toList());
        //设置表数据范围
        for(int i = 0; i < tableInfos.size(); i++){
            ShardingTableDateRange shardingTableDateRange = tableInfos.get(i);
            //设置结束时间
            //原始表第0个
            if(i == 0){
                //如果存在其他表，取最近的一个时间
                if(tableInfos.size()>1){
                    ShardingTableDateRange next = tableInfos.get(1);
                    shardingTableDateRange.setEndDate(next.getTableNameDateTime());
                }
            } else {
                //如果当前记录不是最后一个
                if(i < tableInfos.size()-1){
                    ShardingTableDateRange next = tableInfos.get(i+1);
                    shardingTableDateRange.setEndDate(next.getTableNameDateTime());
                }
            }
            //设置开始时间
            if(i > 0) {
                shardingTableDateRange.setBeginDate(shardingTableDateRange.getTableNameDateTime());
            }
            shardingTableDateRanges.add(shardingTableDateRange);
        }
        if(log.isDebugEnabled()){
            log.info("获取表信息:{}",GsonUtils.toJson(shardingTableDateRanges));
        }
        return shardingTableDateRanges;
    }

    /**
     * 获取表名中时间
     * @param tableName 表名
     * @return 表名中时间
     */
    private static Date getTableNameDateTime(String tableName) {
        try {
            String substring = tableName.substring(tableName.length() - 14);
            return DateTimeUtils.str2Date(substring, DateTimeUtils.FORMAT_yyyyMMddHHmmss);
        } catch (Exception e){
            return null;
        }
    }


    /**
     * 查询条件是否匹配表信息-范围匹配(左开右闭)
     * <P/>
     * 匹配仅6种场景:
     * <P/>
     * 1.tableInfo包含lowerDate、upperDate
     * <P/>
     * 2.lowerDate、upperDate包含tableInfo
     * <P/>
     * 3.lowerDate、upperDate左交叉tableInfo
     * <P/>
     * 4.lowerDate、upperDate右交叉tableInfo
     * <P/>
     * 5.tableInfo没有下界(开始时间)，lowerDate下界(开始时间)小于tableInfo上界(结束时间)
     * <P/>
     * 6.tableInfo没有上界(结束时间)，upperDate上界(结束时间)大于等于tableInfo下界(开始时间)
     * <P/>
     * @param table 表信息
     * @param lowerDate 下界(开始时间)
     * @param upperDate 上界(结束时间)
     * @return 是否满足查询条件的表信息
     */
    public static boolean isShardingTableDateRange(ShardingTableDateRange table, Date lowerDate, Date upperDate) {
        //设置时间日历对象
        Calendar lowerCalendar = Calendar.getInstance();
        if(lowerDate != null){
            //查询下界
            lowerCalendar.setTime(lowerDate);
        }
        Calendar upperCalendar = Calendar.getInstance();
        if(lowerDate != null) {
            //查询上界
            upperCalendar.setTime(upperDate);
        }
        if(lowerDate != null && upperDate != null){
            return isShardingTableDateRangeLowerAndUpper(table, lowerCalendar, upperCalendar);
        } else if(lowerDate == null){
            //没有下界
            return isShardingTableDateRangeUpper(table, upperCalendar);
        } else {
            //没有上界
            return isShardingTableDateRangeLower(table, lowerCalendar);

        }
    }

    private static boolean isShardingTableDateRangeLower(ShardingTableDateRange table, Calendar lowerCalendar) {
        //2022-06-30 00:00:00  <= 表数据  <  2022-10-01 00:00:00
        if(table.getBeginDate() != null && table.getEndDate() != null){
            //表范围结束时间
            Calendar tableEndCalendar = Calendar.getInstance();
            tableEndCalendar.setTime(table.getEndDate());
            //表范围开始时间
            Calendar tableBeginCalendar = Calendar.getInstance();
            tableBeginCalendar.setTime(table.getBeginDate());
            //lowerDate小于tableInfo上界 upperDate大于等于tableInfo下界
            if(lowerCalendar.before(tableEndCalendar)){
                return true;
            } else {
                return false;
            }
        }  else if(table.getEndDate() != null) {
            //表数据  <  2022-06-30 00:00:00
            //表范围结束时间
            Calendar tableEndCalendar = Calendar.getInstance();
            tableEndCalendar.setTime(table.getEndDate());
            //lowerDate小于tableInfo上界
            return lowerCalendar.before(tableEndCalendar);
        } else if(table.getBeginDate() != null){
            return true;
        } else {
            return false;
        }
    }

    private static boolean isShardingTableDateRangeUpper(ShardingTableDateRange table, Calendar upperCalendar) {
        //2022-06-30 00:00:00  <= 表数据  <  2022-10-01 00:00:00
        if(table.getBeginDate() != null && table.getEndDate() != null){
            //表范围结束时间
            Calendar tableEndCalendar = Calendar.getInstance();
            tableEndCalendar.setTime(table.getEndDate());
            //表范围开始时间
            Calendar tableBeginCalendar = Calendar.getInstance();
            tableBeginCalendar.setTime(table.getBeginDate());
            //upperDate大于等于tableInfo下界
            if(upperCalendar.after(tableBeginCalendar) || upperCalendar.equals(tableBeginCalendar)){
                return true;
            } else {
                return false;
            }
        }  else if(table.getEndDate() != null) {
            return true;
        } else if(table.getBeginDate() != null){
            //2022-10-01 00:00:00  <= 表数据
            //表范围开始时间
            Calendar tableBeginCalendar = Calendar.getInstance();
            tableBeginCalendar.setTime(table.getBeginDate());
            //upperDate大于等于tableInfo下界
            return upperCalendar.after(tableBeginCalendar) || upperCalendar.equals(tableBeginCalendar);
        } else {
            return false;
        }
    }

    private static boolean isShardingTableDateRangeLowerAndUpper(ShardingTableDateRange table, Calendar lowerCalendar, Calendar upperCalendar) {
        //2022-06-30 00:00:00  <= 表数据  <  2022-10-01 00:00:00
        if(table.getBeginDate() != null && table.getEndDate() != null){
            //表范围结束时间
            Calendar tableEndCalendar = Calendar.getInstance();
            tableEndCalendar.setTime(table.getEndDate());
            //表范围开始时间
            Calendar tableBeginCalendar = Calendar.getInstance();
            tableBeginCalendar.setTime(table.getBeginDate());
            //检查 lowerDate 小于 upperDate
            if(lowerCalendar.before(upperCalendar) &&
                    //lowerDate小于tableInfo上界 upperDate大于等于tableInfo下界
                    (lowerCalendar.before(tableEndCalendar) && (upperCalendar.after(tableBeginCalendar) || upperCalendar.equals(tableBeginCalendar)))
            ){
                return true;
            } else {
                return false;
            }
        }  else if(table.getEndDate() != null) {
            //表数据  <  2022-06-30 00:00:00
            //表范围结束时间
            Calendar tableEndCalendar = Calendar.getInstance();
            tableEndCalendar.setTime(table.getEndDate());
            //lowerDate小于tableInfo上界
            return lowerCalendar.before(tableEndCalendar);
        } else if(table.getBeginDate() != null){
            //2022-10-01 00:00:00  <= 表数据
            //表范围开始时间
            Calendar tableBeginCalendar = Calendar.getInstance();
            tableBeginCalendar.setTime(table.getBeginDate());
            //upperDate大于等于tableInfo下界
            return upperCalendar.after(tableBeginCalendar) || upperCalendar.equals(tableBeginCalendar);
        } else {
            return false;
        }
    }

    /**
     * 查询条件是否匹配表信息-精准匹配(左开右闭)
     * @param table 表信息
     * @param queryTime 查询时间
     * @return 是否满足查询条件的表信息
     */
    public static boolean isShardingTableDatePrecise(ShardingTableDateRange table, Date queryTime) {
        Calendar date = Calendar.getInstance();
        date.setTime(queryTime);

        Calendar begin = null;
        if(table.getBeginDate() != null){
            begin = Calendar.getInstance();
            begin.setTime(table.getBeginDate());
        }
        Calendar end = null;
        if(table.getEndDate() != null) {
            end = Calendar.getInstance();
            end.setTime(table.getEndDate());
        }
        if(begin != null && end != null){
            //2022-06-30 00:00:00  <= 表数据  <  2022-10-01 00:00:00
            return (date.after(begin) && date.before(end)) || date.equals(begin);
        } else if(end != null) {
            //表数据  <  2022-06-30 00:00:00
            return date.before(end);
        } else if(begin != null){
            //2022-10-01 00:00:00  <= 表数据
            return date.after(begin) || date.equals(begin);
        } else {
            return false;
        }
    }
}
